{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Three layer neural network with variable number of hidden units"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "import matplotlib.pyplot as plt\n",
    "import torch as th\n",
    "import numpy as np\n",
    "from torch.autograd import Variable\n",
    "\n",
    "\n",
    "def train(x, y, w1, w2, b1, b2):\n",
    "\n",
    "\toptimizer = th.optim.Adam([w1, w2, b1, b2], lr = 0.01)\n",
    "\n",
    "\tdef closure():\n",
    "\t\toptimizer.zero_grad()\n",
    "\t\thid = th.tanh(x.mm(w1) + b1.expand(x.size()[0], b1.size()[1]))\n",
    "\t\ty_pred = hid.mm(w2) + b2.expand(x.size()[0], b2.size()[1])\n",
    "\t\tloss = (y_pred - y).pow(2).sum()\n",
    "\t\tloss.backward()\n",
    "\t\treturn loss\n",
    "\n",
    "\tfor t in range(20000):\n",
    "\t\tif t % 1000 == 0:\n",
    "\t\t\tprint(t, closure().data[0])\n",
    "\t\toptimizer.step(closure)\n",
    "\n",
    "\n",
    "def forward(x, w1, w2, b1, b2):\n",
    "\thid = th.tanh(x.mm(w1) + b1.expand(x.size()[0], b1.size()[1]))\n",
    "\treturn hid.mm(w2) + b2.expand(x.size()[0], b2.size()[1])\n",
    "\n",
    "\n",
    "def get_variables(M):\n",
    "\tw1 = Variable(th.randn(1, M).type(th.FloatTensor), requires_grad=True)\n",
    "\tw2 = Variable(th.randn(M, 1).type(th.FloatTensor), requires_grad=True)\n",
    "\tb1 = Variable(th.zeros(1, M).type(th.FloatTensor), requires_grad=True)\n",
    "\tb2 = Variable(th.zeros(1, 1).type(th.FloatTensor), requires_grad=True)\n",
    "\treturn w1, w2, b1, b2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 5.20329141617\n",
      "1000 0.727499842644\n",
      "2000 0.694618046284\n",
      "3000 0.692631304264\n",
      "4000 0.692574679852\n",
      "5000 0.692573845387\n",
      "6000 0.692573845387\n",
      "7000 0.692573845387\n",
      "8000 0.692573904991\n",
      "9000 0.692574203014\n",
      "10000 0.692573964596\n",
      "11000 0.692573904991\n",
      "12000 0.692573964596\n",
      "13000 0.692573964596\n",
      "14000 0.692573904991\n",
      "15000 0.692573845387\n",
      "16000 0.692573904991\n",
      "17000 0.692573964596\n",
      "18000 0.692573845387\n",
      "19000 0.692626535892\n",
      "0 8.6924829483\n",
      "1000 0.206408783793\n",
      "2000 0.0744266733527\n",
      "3000 0.0528785400093\n",
      "4000 0.0456225126982\n",
      "5000 0.0423485040665\n",
      "6000 0.0392330177128\n",
      "7000 0.0352383963764\n",
      "8000 0.0312737934291\n",
      "9000 0.028588289395\n",
      "10000 0.0268693994731\n",
      "11000 0.0256840381771\n",
      "12000 0.0248183142394\n",
      "13000 0.0243049953133\n",
      "14000 0.0235327463597\n",
      "15000 0.0228341985494\n",
      "16000 0.0223071146756\n",
      "17000 0.0218144133687\n",
      "18000 0.0215762909502\n",
      "19000 0.0278392080218\n",
      "0 99.3952026367\n",
      "1000 0.203654840589\n",
      "2000 0.0541744753718\n",
      "3000 0.0097793629393\n",
      "4000 0.00324217788875\n",
      "5000 0.00161337421741\n",
      "6000 0.000908667512704\n",
      "7000 0.000536359031685\n",
      "8000 0.000916306918953\n",
      "9000 0.00021474865207\n",
      "10000 0.000142842254718\n",
      "11000 9.5382296422e-05\n",
      "12000 6.44410101813e-05\n",
      "13000 4.81745773868e-05\n",
      "14000 3.17502053804e-05\n",
      "15000 2.28604658332e-05\n",
      "16000 1.86527977348e-05\n",
      "17000 3.01264899463e-05\n",
      "18000 0.000256099709077\n",
      "19000 7.72356361267e-06\n"
     ]
    }
   ],
   "source": [
    "# Generate training data\n",
    "x = np.arange(0, np.pi * 2, np.pi / 5)\n",
    "tmp = np.array([1 if i % 2 == 0 else -1 for i in range(10)])\n",
    "y = np.sin(x) + tmp * np.abs(np.random.normal(0, 0.15, [10]))\n",
    "\n",
    "input_layer = Variable(th.from_numpy(x.reshape(x.shape + (1,))).type(th.FloatTensor), requires_grad=False)\n",
    "output_layer = Variable(th.from_numpy(y.reshape(y.shape + (1,))).type(th.FloatTensor), requires_grad=False)\n",
    "\n",
    "#init variables\n",
    "case1 = get_variables(1)\n",
    "case2 = get_variables(3)\n",
    "case3 = get_variables(10)\n",
    "\n",
    "\n",
    "train(input_layer, output_layer, *case1)\n",
    "train(input_layer, output_layer, *case2)\n",
    "train(input_layer, output_layer, *case3)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f19ad3edf90>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#predict\n",
    "ix = np.arange(0, np.pi * 2, np.pi / 100)\n",
    "ix2d = Variable(th.from_numpy(ix.reshape(ix.shape + (1,))).type(th.FloatTensor), requires_grad=False)\n",
    "y1 = forward(ix2d, *case1)\n",
    "y2 = forward(ix2d, *case2)\n",
    "y3 = forward(ix2d, *case3)\n",
    "\n",
    "#plot\n",
    "fig = plt.figure()\n",
    "ax1 = fig.add_subplot(1, 3, 1)\n",
    "ax2 = fig.add_subplot(1, 3, 2)\n",
    "ax3 = fig.add_subplot(1, 3, 3)\n",
    "ax1.plot(x, y, 'bx')\n",
    "ax1.plot(ix, y1.data.numpy()[:, 0], 'r')\n",
    "ax1.set_title(\"M = 1\")\n",
    "\n",
    "ax2.plot(x, y, 'bx')\n",
    "ax2.plot(ix, y2.data.numpy()[:, 0], 'r')\n",
    "ax2.set_title(\"M = 3\")\n",
    "\n",
    "ax3.plot(x, y, 'bx')\n",
    "ax3.plot(ix, y3.data.numpy()[:, 0], 'r')\n",
    "ax3.set_title(\"M = 10\")\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
